#include "Texture.hpp"
#include "Renderer.hpp"
#include "../Debug/Logger.hpp"
#include "Utils/Exceptions.hpp"

namespace red {
	Texture::Texture() : mTexture(0), mBPP(GL_RGBA8), mFormat(GL_RGBA){
	}

	Texture::~Texture(){
		Destroy();
	}

	void Texture::Destroy(){
		if(mTexture)
			glDeleteTextures(1, &mTexture);
	}		

	void Texture::LoadFromFile(const std::string &pImage, const Rectangle &pSubRect){
		sf::Image tmp;

		if(!tmp.LoadFromFile(pImage)){
			OmniLog << "File \"" << pImage << "\" is not a valid Image File." << eol;	
			return;
		}else{
			mSize = Vector2I(tmp.GetWidth(), tmp.GetHeight());
			#ifdef _DEBUG
				BaseLog << "DEBUG : \"" << pImage << "\" image loaded." << eol;
			#endif
		}

		// Generation de Binding de la texture a OGL
		glGenTextures(1, &mTexture);
		glBindTexture(GL_TEXTURE_2D, mTexture);

		// Utilisation de linear interpolation pour les min/mag filters
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
		//glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, (f32)Renderer::Call().GetSpecifications().mWantedAnisotropy);

		// Create GL Texture from image, with SubRect use if needed
		if(pSubRect.Width() == 0 && pSubRect.Height() == 0)
			glTexImage2D(GL_TEXTURE_2D, 0, mBPP, mSize.x, mSize.y, 0, mFormat, GL_UNSIGNED_BYTE, const_cast<u8*>(tmp.GetPixelsPtr()));
		else
			glTexSubImage2D(GL_TEXTURE_2D, 0, pSubRect.Origin.x, pSubRect.Origin.y, pSubRect.Width(), pSubRect.Height(), mFormat, GL_UNSIGNED_BYTE, const_cast<u8*>(tmp.GetPixelsPtr()));

		glHint(GL_GENERATE_MIPMAP_HINT, GL_NICEST);
		glGenerateMipmap(GL_TEXTURE_2D);

		glBindTexture(GL_TEXTURE_2D, 0);

		#ifdef _DEBUG
			BaseLog << "DEBUG : Texture created from image \"" << pImage << "\"."/* RAJOUTER LE RECTANGLE UTILISED*/ << eol;
		#endif
	}

	void Texture::Bind() const{
		glBindTexture(GL_TEXTURE_2D, mTexture);
	}

	void Texture::UnBind() const{
		glBindTexture(GL_TEXTURE_2D, 0);
	}
}
